/*
    James McQueen, Tyson Nottingham, Michael Pogson
    TCSS 372 Winter 2012
    SC2 Simulator
    
    sc2sim.h
*/

#ifndef SC2SIM_H
#define SC2SIM_H

#define uchar                   unsigned char
#define ushort                  unsigned short

#define FLAGS_MASK              0xF000
#define N_MASK                  0x8000
#define Z_MASK                  0x4000
#define C_MASK                  0x2000
#define O_MASK                  0x1000
#define LOB_MASK                0xFF
#define HOB_MASK                0xFF00
#define LOW_MASK                0xFFFF
#define HOW_MASK                0xFFFF0000
#define SIGN_MASK               0x8000
#define BITS_PER_BYTE           8
#define BITS_PER_WORD           16

#define NON_NEGATIVE            0
#define NEGATIVE                1

#define MEMORY_SPACE            0x10000
#define MEMORY_START_ADDRESS    0x3000

#define NO_ERROR                2
#define NULL_POINTER_ERROR      3
#define OUT_OF_BOUNDS_ERROR     4
#define INVALID_INSTRUCTION_ERROR    5
#define FILE_NOT_FOUND_ERROR    6
#define FILE_FORMAT_ERROR       7

#define ADD 0
#define SUB 1
#define MUL 2
#define DIV 3
#define AND 4
#define OR 5
#define XOR 6
#define NOT 7
#define SHL 8
#define SHR 9

#ifndef TRUE
#define TRUE -1
#define FALSE 0
#endif

/******************************************************************************/
/* Register                                                                   */
/******************************************************************************/

typedef ushort     Register;
typedef Register*  RegisterPtr;

RegisterPtr register_initialize(void);
uchar register_getLowByte(RegisterPtr r, int* error);
uchar register_getHighByte(RegisterPtr r, int* error);
int register_putLowByte(RegisterPtr r, uchar byte);
int register_putHighByte(RegisterPtr r, uchar byte);
uchar register_signOf(RegisterPtr r);
ushort register_getValue(RegisterPtr r, int* error);
int register_putValue(RegisterPtr r, ushort value);


/******************************************************************************/
/* Register File                                                              */
/******************************************************************************/

#define REGISTER_COUNT    16
#define R0               (uchar) 0x0
#define R1               (uchar) 0x1
#define R2               (uchar) 0x2
#define R3               (uchar) 0x3
#define R4               (uchar) 0x4
#define R5               (uchar) 0x5
#define R6               (uchar) 0x6
#define R7               (uchar) 0x7
#define R8               (uchar) 0x8
#define R9               (uchar) 0x9
#define RA               (uchar) 0xA
#define RB               (uchar) 0xB
#define RC               (uchar) 0xC
#define RD               (uchar) 0xD
#define RE               (uchar) 0xE
#define RF               (uchar) 0xF

#define IP0               (uchar) 0xC
#define IP1               (uchar) 0xD
#define BP                (uchar) 0xE
#define SP                (uchar) 0xF

typedef RegisterPtr*  RegisterFilePtr;

RegisterFilePtr registerFile_initialize(void);
uchar registerFile_getLowByte(RegisterFilePtr rf, uchar reg_num, int* error);
uchar registerFile_getHighByte(RegisterFilePtr rf, uchar reg_num, int* error);
int registerFile_putLowByte(RegisterFilePtr rf, uchar reg_num, uchar byte);
int registerFile_putHighByte(RegisterFilePtr rf, uchar reg_num, uchar byte);
ushort registerFile_getWord(RegisterFilePtr rf, uchar reg_num, int* error);
int registerFile_putWord(RegisterFilePtr rf, uchar reg_num, ushort word);


/******************************************************************************/
/* Memory Module                                                              */
/******************************************************************************/

typedef uchar*  MemoryModulePtr;

MemoryModulePtr memory_initialize(void);
uchar memory_getByte(MemoryModulePtr mm, ushort address, int* error);
int memory_putByte(MemoryModulePtr mm, ushort address, uchar byte);
ushort memory_getWord(MemoryModulePtr mm, ushort address, int* error);
int memory_putWord(MemoryModulePtr mm, ushort address, ushort word);


/******************************************************************************/
/* ALU                                                                        */
/******************************************************************************/

int error;

typedef struct
{
    Register        A;
    Register        B;
    Register        R;
    RegisterPtr     SW;
    RegisterFilePtr rf;
} ALU;

typedef ALU*  ALUPtr;

ALUPtr alu_initialize(RegisterPtr sw, RegisterFilePtr rf);
int alu_putOperandA(ALUPtr alu, ushort word);
int alu_putOperandB(ALUPtr alu, ushort word);
ushort alu_getResult(ALUPtr alu, int* error);
int alu_clearFlags(ALUPtr alu);
int alu_setFlags(ALUPtr alu);
int alu_execute(ALUPtr alu, ushort operation, ushort op1, ushort op2);
int alu_add(ALUPtr alu);
int alu_sub(ALUPtr alu);
int alu_mul(ALUPtr alu);
int alu_div(ALUPtr alu);
int alu_and(ALUPtr alu);
int alu_or(ALUPtr alu);
int alu_xor(ALUPtr alu);
int alu_not(ALUPtr alu);
int alu_shl(ALUPtr alu);
int alu_shr(ALUPtr alu);


/******************************************************************************/
/* Unit Tests                                                                 */
/******************************************************************************/

void testRegister(void);
void testRegisterFile(void);
void testMemoryModule(void);
void testALU(void);
void testTransfers(void);
void printBanner(char* title);

#endif
